"""
工具基类模块

定义所有工具的基类和通用接口。
"""

import json
from abc import ABC, abstractmethod
from dataclasses import dataclass, asdict
from datetime import datetime
from typing import Any, Dict, List, Optional, Union
from pathlib import Path

from rich.console import Console

console = Console()


@dataclass
class ToolResult:
    """工具执行结果"""
    success: bool
    data: Any = None
    message: str = ""
    error: Optional[str] = None
    execution_time: float = 0.0
    metadata: Optional[Dict[str, Any]] = None
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return asdict(self)
    
    def to_json(self) -> str:
        """转换为 JSON 字符串"""
        return json.dumps(self.to_dict(), ensure_ascii=False, indent=2)


class ToolError(Exception):
    """工具执行错误"""
    def __init__(self, message: str, tool_name: str = "", details: Optional[Dict[str, Any]] = None):
        super().__init__(message)
        self.tool_name = tool_name
        self.details = details or {}
        self.timestamp = datetime.now().isoformat()


class BaseTool(ABC):
    """工具基类"""
    
    def __init__(self, name: str, description: str, version: str = "1.0.0"):
        """
        初始化工具
        
        Args:
            name: 工具名称
            description: 工具描述
            version: 工具版本
        """
        self.name = name
        self.description = description
        self.version = version
        self.enabled = True
        self.config = {}
        self._console = Console()
    
    @abstractmethod
    def execute(self, **kwargs) -> ToolResult:
        """
        执行工具
        
        Args:
            **kwargs: 工具参数
            
        Returns:
            ToolResult: 执行结果
        """
        pass
    
    @abstractmethod
    def get_parameters(self) -> Dict[str, Dict[str, Any]]:
        """
        获取工具参数定义
        
        Returns:
            Dict[str, Dict[str, Any]]: 参数定义
        """
        pass
    
    def validate_parameters(self, **kwargs) -> bool:
        """
        验证参数
        
        Args:
            **kwargs: 要验证的参数
            
        Returns:
            bool: 验证是否通过
        """
        try:
            params = self.get_parameters()
            for param_name, param_def in params.items():
                if param_def.get('required', False) and param_name not in kwargs:
                    raise ValueError(f"Required parameter '{param_name}' is missing")
                
                if param_name in kwargs:
                    value = kwargs[param_name]
                    param_type = param_def.get('type', str)
                    
                    # 类型验证
                    if param_type == str and not isinstance(value, str):
                        raise ValueError(f"Parameter '{param_name}' must be a string")
                    elif param_type == int and not isinstance(value, int):
                        raise ValueError(f"Parameter '{param_name}' must be an integer")
                    elif param_type == bool and not isinstance(value, bool):
                        raise ValueError(f"Parameter '{param_name}' must be a boolean")
                    elif param_type == list and not isinstance(value, list):
                        raise ValueError(f"Parameter '{param_name}' must be a list")
                    
                    # 范围验证
                    if 'min' in param_def and value < param_def['min']:
                        raise ValueError(f"Parameter '{param_name}' must be >= {param_def['min']}")
                    if 'max' in param_def and value > param_def['max']:
                        raise ValueError(f"Parameter '{param_name}' must be <= {param_def['max']}")
                    
                    # 选择验证
                    if 'choices' in param_def and value not in param_def['choices']:
                        raise ValueError(f"Parameter '{param_name}' must be one of {param_def['choices']}")
            
            return True
        except Exception as e:
            self._console.print(f"[red]参数验证失败: {e}[/red]")
            return False
    
    def configure(self, config: Dict[str, Any]) -> None:
        """
        配置工具
        
        Args:
            config: 配置字典
        """
        self.config.update(config)
    
    def get_info(self) -> Dict[str, Any]:
        """
        获取工具信息
        
        Returns:
            Dict[str, Any]: 工具信息
        """
        return {
            'name': self.name,
            'description': self.description,
            'version': self.version,
            'enabled': self.enabled,
            'parameters': self.get_parameters(),
            'config': self.config
        }
    
    def enable(self) -> None:
        """启用工具"""
        self.enabled = True
    
    def disable(self) -> None:
        """禁用工具"""
        self.enabled = False
    
    def is_enabled(self) -> bool:
        """检查工具是否启用"""
        return self.enabled
    
    def _create_result(self, success: bool, data: Any = None, message: str = "", 
                      error: Optional[str] = None, execution_time: float = 0.0,
                      metadata: Optional[Dict[str, Any]] = None) -> ToolResult:
        """
        创建工具结果
        
        Args:
            success: 是否成功
            data: 结果数据
            message: 消息
            error: 错误信息
            execution_time: 执行时间
            metadata: 元数据
            
        Returns:
            ToolResult: 工具结果
        """
        return ToolResult(
            success=success,
            data=data,
            message=message,
            error=error,
            execution_time=execution_time,
            metadata=metadata or {}
        )
    
    def _log_info(self, message: str) -> None:
        """记录信息日志"""
        self._console.print(f"[blue][{self.name}][/blue] {message}")
    
    def _log_warning(self, message: str) -> None:
        """记录警告日志"""
        self._console.print(f"[yellow][{self.name}][/yellow] {message}")
    
    def _log_error(self, message: str) -> None:
        """记录错误日志"""
        self._console.print(f"[red][{self.name}][/red] {message}")
    
    def __str__(self) -> str:
        return f"{self.name} v{self.version}: {self.description}"
    
    def __repr__(self) -> str:
        return f"<{self.__class__.__name__}(name='{self.name}', version='{self.version}')>"


class FileTool(BaseTool):
    """文件工具基类"""
    
    def __init__(self, name: str, description: str, version: str = "1.0.0"):
        super().__init__(name, description, version)
        self.supported_extensions = []
        self.max_file_size = 10 * 1024 * 1024  # 10MB
    
    def _validate_file_path(self, file_path: Union[str, Path]) -> Path:
        """
        验证文件路径
        
        Args:
            file_path: 文件路径
            
        Returns:
            Path: 验证后的路径对象
            
        Raises:
            ToolError: 文件路径无效
        """
        path = Path(file_path)
        if not path.exists():
            raise ToolError(f"文件不存在: {path}", self.name)
        
        if not path.is_file():
            raise ToolError(f"路径不是文件: {path}", self.name)
        
        if path.stat().st_size > self.max_file_size:
            raise ToolError(f"文件过大: {path} ({path.stat().st_size} bytes)", self.name)
        
        return path
    
    def _validate_directory_path(self, dir_path: Union[str, Path]) -> Path:
        """
        验证目录路径
        
        Args:
            dir_path: 目录路径
            
        Returns:
            Path: 验证后的路径对象
            
        Raises:
            ToolError: 目录路径无效
        """
        path = Path(dir_path)
        if not path.exists():
            raise ToolError(f"目录不存在: {path}", self.name)
        
        if not path.is_dir():
            raise ToolError(f"路径不是目录: {path}", self.name)
        
        return path


class GitTool(BaseTool):
    """Git 工具基类"""
    
    def __init__(self, name: str, description: str, version: str = "1.0.0"):
        super().__init__(name, description, version)
        self.git_available = self._check_git_availability()
    
    def _check_git_availability(self) -> bool:
        """检查 Git 是否可用"""
        try:
            import subprocess
            result = subprocess.run(['git', '--version'], 
                                  capture_output=True, text=True, timeout=5)
            return result.returncode == 0
        except (subprocess.TimeoutExpired, FileNotFoundError):
            return False
    
    def _run_git_command(self, args: List[str], cwd: Optional[Path] = None) -> str:
        """
        运行 Git 命令
        
        Args:
            args: Git 命令参数
            cwd: 工作目录
            
        Returns:
            str: 命令输出
            
        Raises:
            ToolError: Git 命令执行失败
        """
        if not self.git_available:
            raise ToolError("Git 不可用，请确保已安装 Git", self.name)
        
        try:
            import subprocess
            cmd = ['git'] + args
            result = subprocess.run(cmd, cwd=cwd, capture_output=True, 
                                  text=True, timeout=30)
            
            if result.returncode != 0:
                raise ToolError(f"Git 命令失败: {' '.join(cmd)}\n错误: {result.stderr}", 
                              self.name)
            
            return result.stdout.strip()
        except subprocess.TimeoutExpired:
            raise ToolError("Git 命令超时", self.name)
        except Exception as e:
            raise ToolError(f"Git 命令执行失败: {e}", self.name)
    
    def _get_repo_root(self, path: Optional[Path] = None) -> Path:
        """
        获取 Git 仓库根目录
        
        Args:
            path: 起始路径
            
        Returns:
            Path: 仓库根目录
            
        Raises:
            ToolError: 不在 Git 仓库中
        """
        if path is None:
            path = Path.cwd()
        
        try:
            result = self._run_git_command(['rev-parse', '--show-toplevel'], cwd=path)
            return Path(result)
        except ToolError:
            raise ToolError(f"不在 Git 仓库中: {path}", self.name)


class WebTool(BaseTool):
    """网络工具基类"""
    
    def __init__(self, name: str, description: str, version: str = "1.0.0"):
        super().__init__(name, description, version)
        self.timeout = 30
        self.max_retries = 3
        self.user_agent = "MiniCoder-CLI/1.0"
    
    def _make_request(self, url: str, method: str = "GET", 
                     headers: Optional[Dict[str, str]] = None,
                     data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """
        发送 HTTP 请求
        
        Args:
            url: 请求 URL
            method: HTTP 方法
            headers: 请求头
            data: 请求数据
            
        Returns:
            Dict[str, Any]: 响应数据
            
        Raises:
            ToolError: 请求失败
        """
        try:
            import requests
            
            default_headers = {
                'User-Agent': self.user_agent,
                'Accept': 'application/json, text/plain, */*'
            }
            if headers:
                default_headers.update(headers)
            
            response = requests.request(
                method=method,
                url=url,
                headers=default_headers,
                json=data,
                timeout=self.timeout
            )
            
            response.raise_for_status()
            
            return {
                'status_code': response.status_code,
                'headers': dict(response.headers),
                'content': response.text,
                'json': response.json() if response.headers.get('content-type', '').startswith('application/json') else None
            }
        except requests.exceptions.RequestException as e:
            raise ToolError(f"网络请求失败: {e}", self.name)
        except Exception as e:
            raise ToolError(f"请求处理失败: {e}", self.name)
